#include "sdcard_fs.h"
#include "uart.h"
#include "type.h"
#include "ff.h"
#include "sdcard.h"
#include "diskio.h"
#include "sdram.h" // for SDRAM reading
#include <string.h>

// Filesystem setup
FATFS fatDrive;
FIL file;
FRESULT res;
//BYTE fs_buffer[4096]; // this was for testing
DIR dir;
FILINFO fileinfo;
char filename[13];


/*
 * Helper function for fs_initialize_and_mount.
 * Abstracts away the f_mount functions of ff.c
 */
static void fs_mount(void) {
	res = f_mount(0, &fatDrive);
	if(res != FR_OK) {
		xprintf("Error: f_mount returned: %d\n", res);
		while(1);
	}
	return;
}

void fs_initialize_and_mount(void) {
	disk_initialize(0);
	fs_mount();
	return;
}
/*
 * fs_next_filename
 * Determines what the next recording should be called.
 * Takes in the address (pointer to) a buffer of size 13 or higher.
 * Fills it with a name in the format of:  jamXXXXX.ogg where the
 * XXXXX refers to the number of the jam, starting with 1.
 *
 * If no jam files are available on the disk, it creates the first
 * one as jam00001.ogg.
 */
static void fs_next_filename(void) {
	int digit_tthousand;
	int digit_thousand;
	int digit_hundred;
	int digit_ten;
	int digit_one;
	int combined_number;
	char ch_tth;
	char ch_th;
	char ch_h;
	char ch_t;
	char ch_o;
	int highest_number = 0;

	res = f_opendir(&dir, "/");
	if(res != FR_OK) {
		xprintf("Error: f_opendir returned: %d\n", res);
	}

	while((f_readdir(&dir, &fileinfo) == FR_OK) && fileinfo.fname[0]) {

		// Check if filename is of format "jamXXXXX.ogg"
		if(fileinfo.fname[0] != 'j' || fileinfo.fname[1] != 'a' || fileinfo.fname[2] != 'm'
				|| fileinfo.fname[8] != '.' || fileinfo.fname[9] != 'o' || fileinfo.fname[10] != 'g' || fileinfo.fname[11] != 'g') {
			continue;
		}

		digit_thousand = 0;
		digit_hundred = 0;
		digit_ten = 0;
		digit_one = 0;
		combined_number = 0;

		/* Filename format is:
		 * jam00001.ogg
		 */
		digit_tthousand= fileinfo.fname[3]-48;
		digit_thousand = fileinfo.fname[4]-48;
		digit_hundred  = fileinfo.fname[5]-48;
		digit_ten	   = fileinfo.fname[6]-48;
		digit_one 	   = fileinfo.fname[7]-48;
		combined_number = (digit_tthousand*10000) + (digit_thousand*1000) + (digit_hundred*100) + (digit_ten*10) + (digit_one);

		if(combined_number > highest_number) {
			highest_number = combined_number;
		}
	}
	highest_number++; // increment to the number we want.

	// Sequence to determine each digit so we can convert it to a char.
	digit_tthousand=  (highest_number)/10000;
	highest_number -= (digit_tthousand * 10000);

	digit_thousand =  ((highest_number)/1000);
	highest_number -= (digit_thousand * 1000);

	digit_hundred  =  ((highest_number)/100);
	highest_number -= (digit_hundred * 100);

	digit_ten      =  ((highest_number)/10);
	highest_number -= (digit_ten * 10);

	digit_one	   =  ((highest_number));

	ch_tth= (char) digit_tthousand+48;
	ch_th = (char) digit_thousand+48;
	ch_h  = (char) digit_hundred+48;
	ch_t  = (char) digit_ten+48;
	ch_o  = (char) digit_one+48;

	filename[0] = 'j';
	filename[1] = 'a';
	filename[2] = 'm';
	filename[3] = ch_tth;
	filename[4] = ch_th;
	filename[5] = ch_h;
	filename[6] = ch_t;
	filename[7] = ch_o;
	filename[8] = '.';
	filename[9] = 'o';
	filename[10] = 'g';
	filename[11]= 'g';
	filename[12] = 0;

	return;
}

static FRESULT set_timestamp (
    char *obj,     /* Pointer to the file name */
    int year,
    int month,
    int mday,
    int hour,
    int min,
    int sec
)
{
    FILINFO fno;

    fno.fdate = (WORD)(((year - 1980) * 512U) | month * 32U | mday);
    fno.ftime = (WORD)(hour * 2048U | min * 32U | sec / 2U);

    return f_utime(obj, &fno);
}


/*
 * Takes in the start address (typically SDRAM_BASE_ADDR) and
 * number of bytes and does an f_write directly from the SDRAM.
 */
void fs_create_file(BYTE* start, DWORD numBytes) {
	UINT bytesWritten = 0;
	int bytes_per_cycle = 512;
	int numCycles = 0;
	int bytesLeft = numBytes;
	BYTE* pos = start;
	int i;

	// Determine how many [bytes_per_cycle] Byte writes it must do (i.e. 1026byte write must have N * [bytes_per_cycle] cycles.)
	for(i=numBytes; i>0; i-=bytes_per_cycle) {
		numCycles++;
	}

	// Generate next filename.
	fs_next_filename();

	// Open the file (create it.)
	res = f_open(&file, filename, FA_CREATE_NEW | FA_WRITE );
	if(res != FR_OK) {
		xprintf("Error: f_open returned: %d\n", res);
		while(1);
	}

	// Pre-allocate clusters
	res = f_lseek(&file, numBytes);
	res = f_lseek(&file, 0); // move to data start

	i=0;
	while(i < numCycles) {
		//xprintf("Cycle %d:\n", i);
		if(i != 0) {
			//xprintf("\tSeeking to %d...\n", i*bytes_per_cycle);
			res = f_lseek(&file, i*bytes_per_cycle); // move to the end of the file to append data
		}
		//xprintf("\tWriting from 0x%08x (%d bytes)\n", pos, (i == numCycles-1) ? (UINT)bytesLeft : (UINT)bytes_per_cycle);

		res = f_write(&file, pos, (i == numCycles-1) ? (UINT)bytesLeft : (UINT)bytes_per_cycle, &bytesWritten);
		if(res != FR_OK) {
			xprintf("Error: f_write on cycle %d\n", i);
		}

		pos += bytes_per_cycle; 	// increase position pointer in SDRAM
		i++;						// increase the current cycle number
		bytesLeft -= bytesWritten;
	}

	// Remove any unwritten file space.
	// This probably won't be necessary, but it's nice to have.
	res = f_truncate(&file);


	// Should be done now. Check bytes written.
	xprintf("File %s written!\n", filename);

	// Close the file.
	res = f_close(&file);
	if(res != FR_OK) {
		xprintf("Error: f_close returned: %d\n", res);
	}

	// Set the timestamp! (leet)
	res = set_timestamp(filename, 2011, 6, 2, 16, 20, 0); // set to 6/2/2011 @ 4:20pm
	if(res != FR_OK) {
		xprintf("Error: setting timestamp. Res = %d\n", res);
	}

	// Flash the light twice after the recording is done.
	LED_off();
	delay();
	LED_on();
	delay();
	LED_off();
	delay();
	LED_on();
	delay();
	LED_off();
	return;
}

